import { CMutationItem } from './editorModels';

export function useMotation () {
  debugger
  let list : CMutationItem[] = [];
  var index = 0;
    
  const observer = new MutationObserver(function(mutations, observer) {
      list.splice(index+1);
      mutations.map(function(record) {
      var target = record.target;target.childNodes
      console.log(record);
      //删除元素或者是添加元素;
      if( record.type === "childList" ) {
        //如果是删除元素;
        if(record.removedNodes.length !== 0) {
          //获取元素的相对索引;
          var indexs = getIndexs(target.childNodes , record.removedNodes );
          list.push({
            "undo": function() {
              disconnect();
              addChildren(record,  record.removedNodes ,indexs );
              reObserve();
            },
            "redo": function() {
              disconnect();
              removeChildren(record,  record.removedNodes );
              reObserve();
            }
          });
                      
        };
        //如果是添加元素;
        if(record.addedNodes.length !== 0) {          
          //获取元素的相对索引;
          var indexs = getIndexs(target.childNodes , record.addedNodes);
          list.push({
            "undo" : function() {
              disconnect();
              removeChildren(record, record.addedNodes);
              reObserve();
            },
            "redo" : function () {
              disconnect();
              addChildren(record, record.addedNodes, indexs);
              reObserve();
            }
          })
        };
      }else if( record.type === "characterData" ) {
        var oldValue = record.oldValue;
        var newValue = record.target.textContent //|| record.target.innerText, 不准备处理IE789的兼容，所以不用innerText了;
        list.push({
          "undo" : function() {
            disconnect();
            target.textContent = oldValue;
            reObserve();
          },
          "redo" : function () {
            disconnect();
            target.textContent = newValue;
            reObserve();
          }
        });
      //如果是属性变化的话style, dataset, attribute都是属于attributes发生改变, 可以统一处理;
      }else if(record.type === "attributes") {
        var oldValue = record.oldValue;        
        var attributeName = record.attributeName;
        var newValue = record.target.nodeValue
        list.push({
          "undo" : function() {
            disconnect();
            document.body.setAttribute(attributeName || '', oldValue || '')
            //target.setAttribute(attributeName, oldValue);
            reObserve();
          },
          "redo" : function () {
            disconnect();
            document.body.setAttribute(attributeName || '', newValue || '');
            
            reObserve();
          }
        });
      };
      //重新设置索引;
      index = list.length-1;
    })
  });  
  
  const removeChildren = (record: MutationRecord, nodes : NodeList) => {
    for(var i= 0, len= nodes.length; i<len; i++ ) {      
      record.target.removeChild( nodes[i] );
    };
  };

  const addChildren = (record : MutationRecord, nodes : NodeList, indexs : number[]) => {
    for(var i= 0, len= nodes.length; i<len; i++ ) {
      if(record.target.childNodes[indexs[i]]) {
        record.target.insertBefore(nodes[i], record.target.childNodes[indexs[i]])
      }else{
          record.target.appendChild(nodes[i]);
      };
    };
  };

  const indexOf = (record : NodeListOf<ChildNode>, node : Node) => {
    return Array.prototype.indexOf.call(record, node)
  };

  const getIndexs = (record : NodeListOf<ChildNode>, nodes : NodeList) => {
    var result = [];
    for(var i = 0; i < nodes.length; i++) {
      result.push(indexOf(record, nodes[i]) );
    };
    return result;
  }

  const disconnect = () => {
    return observer.disconnect();
  };

  const save = (obj : any) => {
    if(!obj.undo)return alert("传进来的第一个参数必须有undo方法才行");
    if(!obj.redo)return alert("传进来的第一个参数必须有redo方法才行");
    list.push(obj);
  };

  const reset = () => {
    list = [];
    index = 0
  };

  const splice = (index: number) => {
    list.splice(index)
  }

  const redo = () => {
    if(canRedo()){
      index++;
      list[index].redo(); 
    }     
  };

  const undo = () => {
    if(canUndo()){
      list[index].undo();
      index--;
    }    
  };

  const canUndo: () => boolean = () => {
    return index !== -1;
  };

  const canRedo = () => {
    return list.length-1 !== index;
  };

  const options = {
    'childList': true,
    'subtree': true,
    'attributes' : true,
    'characterData' : true,
    'attributeOldValue' : true,
    'characterDataOldValue' : true
  }

  const reObserve = () => {
    observer.observe(document.body, options)
  };

  return {
    list,
    index,
    observer,
    removeChildren,
    addChildren,
    disconnect,
    save,
    reset,
    splice,
    undo, 
    redo,
    options,
    canUndo,
    canRedo
  }
}